package com.wangxiandeng.swipecardrecyclerview;

import ohos.agp.components.AttrSet;
import ohos.agp.components.BaseItemProvider;
import ohos.agp.components.Component;
import ohos.agp.components.StackLayout;
import ohos.agp.database.DataSetSubscriber;
import ohos.agp.render.Canvas;
import ohos.agp.utils.Point;
import ohos.app.Context;

public class SwipeCardRecyclerView extends BaseFlingAdapterView {
  private int MIN_ADAPTER_STACK = DEFAULT_MAX_VISIBLE;
  private float ROTATION_DEGREES = 15.f;

  private BaseItemProvider mAdapter;
  private int LAST_OBJECT_IN_STACK = 0;
  private onFlingListener mFlingListener;
  private AdapterDataSetObserver mDataSetObserver;
  private boolean mInLayout = false;
  private Component mActiveCard = null;
  private OnItemClickListener mOnItemClickListener;
  private FlingCardListener flingCardListener;
  private ProviderComponent providerComponent;
  private Point mLastTouchPoint;
  private int slideType = 0;
  // 图片倾斜
  private boolean imageSpin = true;
  private boolean isCardOverlap = false;

  public SwipeCardRecyclerView(Context context) {
    this(context, null);
  }

  public SwipeCardRecyclerView(Context context, AttrSet attrSet) {
    this(context, attrSet, null);
  }

  public SwipeCardRecyclerView(Context context, AttrSet attrSet, String styleName) {
    super(context, attrSet, styleName);
  }

  public void SlideType(int slideType) {
    this.slideType = slideType;
  }

  public void setImageSpin(boolean imageSpin) {
    this.imageSpin = imageSpin;
  }

  public void setIsCardOverlap(boolean isCardOverlap) {
    this.isCardOverlap = isCardOverlap;
    setCardOverlap(isCardOverlap);
  }

  /**
   * A shortcut method to set both the listeners and the adapter.
   *
   * @param context  The activity context which extends onFlingListener, OnItemClickListener or
   *                both
   * @param mAdapter The adapter you have to set.
   */
  public void init(final Context context, BaseItemProvider mAdapter) {
    if (context instanceof onFlingListener) {
      mFlingListener = (onFlingListener) context;
    } else {
      throw new RuntimeException("ability does not implement SwipeFlingAdapterView" +
          ".onFlingListener");
    }
    if (context instanceof OnItemClickListener) {
      mOnItemClickListener = (OnItemClickListener) context;
    }
    setItemProvider(mAdapter);
  }

  @Override
  public Component getSelectedComponent() {
    return mActiveCard;
  }

  @Override
  public void postLayout() {
    if (!mInLayout) {
      super.postLayout();
    }
  }

  @Override
  public void onRefreshed(Component component) {
    // if we don't have an adapter, we don't need to do anything
    if (mAdapter == null) {
      return;
    }
    mInLayout = true;
    Component topCard = getComponentAt(LAST_OBJECT_IN_STACK);
    if (mActiveCard != null && topCard != null && topCard == mActiveCard) {
      if (this.flingCardListener.isTouching()) {
        Point lastPoint = this.flingCardListener.getLastPoint();
        if (this.mLastTouchPoint == null || !this.mLastTouchPoint.equals(lastPoint)) {
          this.mLastTouchPoint = lastPoint;
          removeComponents(0, LAST_OBJECT_IN_STACK);
        }
      }
    } else {
      setTopView();
    }
    mInLayout = false;
  }

  @Override
  public void onDraw(Component component, Canvas canvas) {
    final int adapterCount = mAdapter.getCount();
    if (adapterCount <= MIN_ADAPTER_STACK) {
      mFlingListener.onAdapterAboutToEmpty(adapterCount);
    }
  }

  /**
   * Set the top view and add the fling listener
   */
  private void setTopView() {
    if (getChildCount() > 0) {
      mActiveCard = getComponentAt(LAST_OBJECT_IN_STACK);
      if (mActiveCard != null) {
        flingCardListener =
            new FlingCardListener(
                this,
                slideType, mActiveCard, imageSpin ? true : false,
                mAdapter.getItem(0),
                ROTATION_DEGREES,
                new FlingCardListener.FlingListener() {
                  @Override
                  public void onCardExited() {
                    mActiveCard = null;
                    mFlingListener.removeFirstObjectInAdapter();
                  }

                  @Override
                  public void leftExit(Object dataObject) {
                    mFlingListener.onLeftCardExit(dataObject);
                  }

                  @Override
                  public void rightExit(Object dataObject) {
                    mFlingListener.onRightCardExit(dataObject);
                  }

                  @Override
                  public void onClick(Object dataObject) {
                    if (mOnItemClickListener != null) {
                      mOnItemClickListener.onItemClicked(0, dataObject);
                    }
                  }

                  @Override
                  public void onScroll(float scrollProgressPercent) {
                    mFlingListener.onScroll(scrollProgressPercent);
                  }
                });
        flingCardListener.setComponentContainer(this);
        mActiveCard.setTouchEventListener(flingCardListener);
      }
    }
  }

  public FlingCardListener getTopCardListener() throws NullPointerException {
    if (flingCardListener == null) {
      throw new NullPointerException();
    }
    return flingCardListener;
  }

  public ProviderComponent getCardVesselListener() throws NullPointerException {
    if (providerComponent == null) {
      throw new NullPointerException();
    }
    return providerComponent;
  }

  public void setMinStackInAdapter(int MIN_ADAPTER_STACK) {
    this.MIN_ADAPTER_STACK = MIN_ADAPTER_STACK;
  }

  @Override
  public BaseItemProvider getItemProvider() {
    return mAdapter;
  }

  @Override
  public void setItemProvider(BaseItemProvider provider) {
    if (mAdapter != null && mDataSetObserver != null) {
      mAdapter.removeDataSubscriber(mDataSetObserver);
      mDataSetObserver = null;
    }
    mAdapter = provider;
    if (mAdapter != null && mDataSetObserver == null) {
      mDataSetObserver = new AdapterDataSetObserver();
      mAdapter.addDataSubscriber(mDataSetObserver);
    }
    super.setItemProvider(provider);
  }

  public void setFlingListener(onFlingListener onFlingListener) {
    this.mFlingListener = onFlingListener;
  }

  public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
    this.mOnItemClickListener = onItemClickListener;
  }

  @Override
  public LayoutConfig createLayoutConfig(Context context, AttrSet attrSet) {
    return new StackLayout.LayoutConfig(context, attrSet);
  }

  /**
   * The observer
   */
  private class AdapterDataSetObserver extends DataSetSubscriber {
    @Override
    public void onChanged() {
      postLayout();
    }

    @Override
    public void onInvalidated() {
      postLayout();
    }
  }

  public interface OnItemClickListener {
    void onItemClicked(int itemPosition, Object dataObject);
  }

  public interface onFlingListener {
    void removeFirstObjectInAdapter();

    void onLeftCardExit(Object dataObject);

    void onRightCardExit(Object dataObject);

    void onAdapterAboutToEmpty(int itemsInAdapter);

    void onScroll(float scrollProgressPercent);
  }
}
